#pragma once

#include "log.hpp"
#include "Sock.hpp"
#include "epoll.hpp"
#include <memory>
#include <cstring>



class Epollserver
{
    static const int epoll_num_max = 1000;

public:
    Epollserver(uint16_t port)
    :_port(port) ,
    _sock_ptr(new Sock),
    _epoll_ptr(new Epoll)
    {}
    
    void Init()
    {
        // 进行初始化,
        // 1. 创建套接字
        // 2. 绑定
        // 3. 监听
        // 4. 将网络套接字加入到监听模式

        _sock_ptr->Socket();
        _sock_ptr->Bind(_port);
        _sock_ptr->Listen();

        _epoll_ptr->add(_sock_ptr->Get_fd() , EPOLLIN);
    }

    void Accept()
    {
        int newfd = _sock_ptr->Accept();
        if(newfd < 0)
        {
            Log(Warning) << "sock accept fail";
        }
        else
        {
            _epoll_ptr->add(newfd , EPOLLIN);
            Log(Info) << "sock accept sucess , fd : " << newfd;
        }
    }

    void Recv(int fd)
    {
        char buffer[1024];
        int n = read(fd , buffer , sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = 0;
            std::string ret = "echo#";
            ret += buffer;
            write(fd , ret.c_str() , ret.size());
        }
        else if(n == 0)
        {
            // 对方关闭文件描述符
            _epoll_ptr->del(fd);
            close(fd);
        }
        else
        {
            // 出错
            Log(Warning) << "read fail";
        }
    }

    void dispatcher(int n)
    {
        // 对所有需要进行处理的文件描述符进行派发
        int listensock = _sock_ptr->Get_fd();
        for(int i = 0 ; i < n ; i++)
        {
            int fd = _event_array[i].data.fd;
            uint32_t events = _event_array[i].events;

            if(fd == listensock)
            {
                // 有新的连接进行Accept
                Accept();
            }
            else
            {
                // 正常文件描述符就绪,直接进行读取即可
                Recv(fd);
            }
        }
    }


    void Run()
    {
        while(1)
        {
            int n = _epoll_ptr->wait(_event_array , epoll_num_max , 1000);
            if(n > 0)
            {
                // 对拿上来的连接进行处理
                dispatcher(n);
            }
            else if(n == 0)
            {
                continue;
            }
            else
            {
                Log(Error) << "epoll_wait error";
            }
        }
    }

private:
    std::shared_ptr<Sock> _sock_ptr;
    std::shared_ptr<Epoll> _epoll_ptr;
    uint16_t _port;

    struct epoll_event _event_array[epoll_num_max];
};